package pl.edu.pw.MidEmu.Sensing.Sensors;

import java.util.UUID;
import java.util.Vector;

import pl.edu.pw.MidEmu.Sensing.Processing.ProcessingAlgorithm;
import pl.edu.pw.MidEmu.Sensing.Values.IValue;

/**
 * Class representing abstract sensor
 * Servers as base implementation for each sensor type 
 * 
 * @author Mateusz Starodab
 *
 */
public abstract class ASensor
{
	private ProcessingAlgorithm algorithm;

	private String id = UUID.randomUUID().toString();

	private IValue initialValue;

	private IValue value;

	/**
	 * Adds row of data to sensor characteristics
	 * @param data Vector with data
	 * @param name Name of this sensor
	 * @param sensorPort port of this sensor
	 */	
	private void addData(Vector<Vector<String>> data, String name, String sensorPort)
	{
		Vector<String> row = new Vector<String>();
		row.add(name);
		row.add(sensorPort);
		data.add(row);
	}

	@Override
	/**
	 * Checks if obj is same object as this sensor
	 * @return True if sensor is the same sensor as this instance
	 */
	public boolean equals(Object obj)
	{
		if (obj != null)
			if (obj instanceof ASensor)
				return ((ASensor) obj).id.equals(this.id);
		return false;
	}

	/**
	 * Gets sensor name for use with CKB component
	 * @return CKB name of the sensor
	 */
	public abstract String getCkbName();

	/**
	 * Gets id of the sensor
	 * @return Sensor ID
	 */
	public String getId()
	{
		return id;
	}

	/**
	 * Processing algorithm that runs this sensor
	 * @return Processing algorithm
	 */
	public ProcessingAlgorithm getProcessingAlgorithm()
	{
		return algorithm;
	}

	/**
	 * Gets sensor identification and configuration data data
	 * @return List of properties describing this sensor
	 */
	public Vector<Vector<String>> getSensorData()
	{
		Vector<Vector<String>> data = new Vector<Vector<String>>();

		addData(data, "InitialValue", initialValue.getValueAsText());
		addData(data, "ID", id);

		return data;
	}

	/**
	 * Returns sensor status as text
	 * @return Sensor status as text
	 */
	public String getStatusAsText()
	{
		return isRunning() ? "Running" : "Suspended";
	}

	/**
	 * Gets sensor value
	 * @return Value returned by this sensor
	 */
	public IValue getValue()
	{
		return value;
	}

	@Override
	/**
	 * Hash code of this sensor
	 * @returns Hashcode
	 */
	public int hashCode()
	{
		return super.hashCode() + id.hashCode();
	}

	/**
	 * Checks if this sensor is running
	 * @return True is sensor is running
	 */
	public boolean isRunning()
	{
		return algorithm.isRunning();
	}

	/**
	 * Parses value and sets it to the sensor
	 * @param string Value to parse
	 */
	public void parseValue(String string)
	{
		this.value = value.parse(string);
	}

	/**
	 * Pauses sensor processing
	 */
	public void pause()
	{
		algorithm.pause();
	}

	/**
	 * Resumes sensor processing
	 */
	public void resume()
	{
		algorithm.unpause();
	}

	/**
	 * Sets initial sensor reading
	 * @param value Initial sensor reading
	 */
	public void setInitialReading(IValue value)
	{
		this.value = value;
		this.initialValue = value;
	}

	/**
	 * Sets processing algorithm that will run this server
	 * @param algorithm Processing algorithm to be set
	 */
	public void setProcessingAlgorithm(ProcessingAlgorithm algorithm)
	{
		this.algorithm = algorithm;
		this.algorithm.setSensor(this);
	}

	/**
	 * Starts sensor processing 
	 */
	public void startProcessing()
	{
		algorithm.start();
	}

	/**
	 * Terminates sensor 
	 */
	public void terminate()
	{
		algorithm.terminate();
	}

	@Override
	/**
	 * Gets string representation of this sensor
	 */
	public abstract String toString();
}
